#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <arpa/inet.h>


#include "31wrap.h"

#define SERV_PORT 8000



int main(int argc, char *argv[]){

	int i, j, n, nready;

	int maxfd = 0;
	int listenfd, connfd;
	char buf[BUFSIZ];


	struct sockaddr_in serv_addr, cli_addr;
	socklen_t cli_addr_len;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	int opt =1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));

	bzero(&serv_addr, sizeof(serv_addr));   // The address structure is cleared
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(SERV_PORT);

	Bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));  // bind

	Listen(listenfd, 128);   // Set the maximum number of connections to a service at a time

	fd_set rset, allset;   /* rset 读事件文件描述符集合，allset用来暂存 */
	maxfd = listenfd;

	FD_ZERO(&allset);
	FD_SET(listenfd, &allset);


	while (1) {
		rset = allset;   /* 构造select监控文件描述符集 */
		nready = select(maxfd+1, &rset, NULL, NULL, NULL);
		if (nready < 0)
			perr_exit("select error");
		if (FD_ISSET(listenfd, &rset)){   /* 说明有新的客户端连接请求 */
			cli_addr_len = sizeof(cli_addr);
			connfd = Accept(listenfd, (struct sockaddr *)&cli_addr, &cli_addr_len); 			
			FD_SET(connfd, &allset);  /*向监控文件描述符集合allset中添加新的文件描述符connfd */
			if (maxfd < connfd){
				maxfd = connfd;	
			}	
			if (0 == --nready)  /* 只有listenfd有事件，后续的for 不需要执行 */
				continue;

		}

		for (i = listenfd+1; i <= maxfd; i++){ /* 检查哪个clients有数据就绪 */
			if (FD_ISSET(i, &rset)) {
				if ((n = Read(i, buf, sizeof(buf))) == 0) { /* 当client关闭连接时，服务端也关闭对应连接 */
					Close(i);
					FD_CLR(i, &allset);
				}else if (n == -1){
					perr_exit("read error");
				}else if (n > 0){
					for (j = 0; j < n; j++)
						buf[j] = toupper(buf[j]);
					Write(i, buf, n);
					Write(STDOUT_FILENO, buf, n);
				}
			}	
		}

	}


	Close(listenfd);
	return 0;
}
